import random

class Game:
    def __init__(self, rows, cols):
        self.world = self.init_map(rows, cols)
        self.random_map()
        self.next_world = self.init_map(rows, cols)
        self.force_active_queue = []

    def force_active_cell(self, cell):
        self.force_active_queue.append(cell)

    def init_map(self, rows, cols):
        self.rows = rows
        self.cols = cols
        return [[0 for c in range(cols)] for r in range(rows)]

    def random_map(self):
        self.apply(self.world, lambda r, c : int(random.randint(0, 7) == 0))
        
    def render(self, draw_cell):
        self.apply(self.world, lambda r, c : (draw_cell(r, c) if self.world[r][c] else 0))
    
    def update(self):
        self.apply(self.next_world, lambda r, c : self.next_cell(self.world, r, c))
        self.apply(self.world, lambda r, c : self.next_world[r][c])
        while len(self.force_active_queue) > 0:
            n = self.force_active_queue.pop()
            self.world[n[0]][n[1]] = not self.world[n[0]][n[1]]
    
    def apply(self, grid, func):
        for r in range(len(grid)):
            for c in range(len(grid[r])):
                grid[r][c] = func(r, c)

    def count_neighbors(self, w, r, c):
        sum = -1 if w[r][c] else 0
        
        for nr in range(r - 1, r + 1 + 1):
            for nc in range(c - 1, c + 1 + 1):
                if nr < 0:
                    nr = self.rows - 1
                elif nr >= self.rows:
                    nr = 0
                
                if nc < 0:
                    nc = self.cols - 1
                elif nc >= self.cols:
                    nc = 0
                    
                if w[nr][nc]:
                    sum += 1
     
        return sum

    def next_cell(self, current_world, r, c):
        n = self.count_neighbors(current_world, r, c)
        if n == 3:
            return 1
        elif n == 2:
            return current_world[r][c]
        else:
            return 0